package com.note.simpleshop.redis;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.connection.RedisStringCommands;
import org.springframework.data.redis.connection.ReturnType;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.nio.charset.Charset;

/**
 * @author superchen
 * @since 2018/5/16
 **/
@Component
public class RedisLock {
    private static final int EXPIRE_TIME=20;
    private static final String RELEASE_LOCK_SCRIPT = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    private final Logger logger = LoggerFactory.getLogger(RedisLock.class);
    public boolean tryLock(String key, String requestId) {
        if(logger.isDebugEnabled()) {
            logger.debug("获取锁 key={},requestId={}",key,requestId);
        }
        try {
            return redisTemplate.execute((RedisCallback<Boolean>) redisConnection -> {
                return redisConnection.set(key.getBytes(Charset.forName("UTF-8")), requestId.getBytes(Charset.forName("UTF-8")), Expiration.seconds(EXPIRE_TIME), RedisStringCommands.SetOption.SET_IF_ABSENT);
            });
        } catch (Exception e) {
            logger.error("获取锁失败", e);
        }
        return false;
    }
    public boolean releaseLock(String key, String requestId) {
        if(logger.isDebugEnabled()) {
            logger.debug("释放锁 key={},requestId={}",key,requestId);
        }
        try {
            return redisTemplate.execute((RedisCallback<Boolean>) redisConnection -> {
                return redisConnection.eval(RELEASE_LOCK_SCRIPT.getBytes(Charset.forName("UTF-8")), ReturnType.BOOLEAN, 1, key.getBytes(Charset.forName("UTF-8")), requestId.getBytes(Charset.forName("UTF-8")));
            });
        } catch (Exception e) {
            logger.error("释放锁失败", e);
        }
        return false;
    }
}
